package com.js.data.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.js.data.common.dto.UserMenuVO;
import com.js.data.common.exception.ApiException;
import com.js.data.system.dto.MenuDTO;
import com.js.data.system.entity.SysMenu;
import com.js.data.system.mapper.SysMenuMapper;
import com.js.data.system.service.MenuService;
import com.js.data.system.service.RoleMenuService;
import com.js.data.system.vo.CommonTreeVO;
import com.js.data.system.vo.MenuDetailVO;
import com.js.data.system.vo.MenuTreeVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单 服务实现类
 * </p>
 *
 * @author wujj
 * @since 2022-09-06
 */
@Service
public class MenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements MenuService {


    @Resource
    private RoleMenuService roleMenuService;

    /**
     * 菜单列表
     *
     * @param parentId 父id
     * @return List
     */
    @Override
    public List<MenuTreeVO> treeMenu(Long parentId) {
        if (Objects.isNull(parentId)) {
            parentId = 0L;
        }
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getParentId, parentId).orderByAsc(SysMenu::getSortBy);
        List<MenuTreeVO> retList = new ArrayList<>();
        list(queryWrapper).forEach(menu -> {
            MenuTreeVO menuTreeVO = new MenuTreeVO();
            BeanUtils.copyProperties(menu, menuTreeVO);
            retList.add(menuTreeVO);
        });
        return retList;
    }

    /**
     * 新增菜单
     *
     * @param menuDTO 菜单表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveMenu(MenuDTO menuDTO) {
//        if (lambdaQuery().eq(SysMenu::getName, menuDTO.getName()).one() != null) {
//            throw new ApiException("菜单标题已存在");
//        }
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(menuDTO, sysMenu);
        Long pid = sysMenu.getParentId();
        SysMenu parentMenu = null;
        if (pid != null && pid != 0) {
            parentMenu = getById(pid);
            Optional.ofNullable(parentMenu).orElseThrow(() -> new ApiException("父菜单不存在"));
            sysMenu.setParentIds(parentMenu.getParentIds() + "," + pid);
        }else {
            sysMenu.setParentIds("0");
        }
        save(sysMenu);
        // 数据保存成功,父级"直接子集数量"加1
        if (Objects.nonNull(parentMenu)) {
            getBaseMapper().incrSubCount(pid);
        }
    }


    /**
     * 修改菜单
     *
     * @param id      菜单id
     * @param menuDTO 菜单表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editMenu(Long id, MenuDTO menuDTO) {
        Long newParentId = menuDTO.getParentId();
        if (id.equals(newParentId)) {
            throw new ApiException("上级不能为自己");
        }
//        if (lambdaQuery().eq(SysMenu::getName, menuDTO.getName()).ne(SysMenu::getId, id).one() != null) {
//            throw new ApiException("菜单标题已存在");
//        }

        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(menuDTO, menu);
        menu.setId(id);
        SysMenu sysMenuEx = getById(id);
        Long oldParentId = sysMenuEx.getParentId();
        //如果父级是隐藏，子级不能修改成显示
        SysMenu parentMenu = getById(newParentId);
//        if (menu.getState() == 1 && newParentId != 0) {
//            if (parentMenu.getHidden() == 0) {
//                throw new ApiException("父级菜单隐藏不能设置子级显示");
//            }
//        }
//        //隐藏菜单子级菜单也隐藏,显示菜单子级也显示
//        if (!menu.getState().equals(sysMenuEx.getHidden())) {
//            List<Long> childIdList = getBaseMapper().selectAllChildIdByPid(id);
//            if (CollectionUtil.isNotEmpty(childIdList)) {
//                SysMenu childMenu = new SysMenu();
//                childMenu.setHidden(menu.getHidden());
//                lambdaUpdate().in(SysMenu::getId, childIdList).update(childMenu);
//            }
//        }
        // 修改了父节点
        if (!oldParentId.equals(newParentId)) {
            // 原来上级子节点数量 -1
            getBaseMapper().decrSubCount(sysMenuEx.getParentId());
            // 现在上级子节点数量 +1
            getBaseMapper().incrSubCount(newParentId);
            menu.setParentIds(parentMenu.getParentIds() + "," + newParentId);
            //修改所有子节点的parentIds
            SysMenu childMenu = new SysMenu();
            childMenu.setParentIds(menu.getParentIds() + "," + id);
            List<Long> childIdList = getBaseMapper().selectAllChildIdByPid(id);
            if (CollectionUtil.isNotEmpty(childIdList)){
                lambdaUpdate().in(SysMenu::getId, childIdList).update(childMenu);
            }

        }
        updateById(menu);
    }

    /**
     * 删除菜单
     *
     * @param id 菜单ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Long id) {
        // 删除子节点
        SysMenu sysMenuEx = this.getById(id);
        Optional.ofNullable(sysMenuEx).orElseThrow(() -> new ApiException("菜单不存在"));
        removeById(id);
        List<Long> childIdList = getBaseMapper().selectAllChildIdByPid(id);
        this.removeByIds(childIdList);
        if (0 != sysMenuEx.getParentId()) {
            SysMenu parentMenu = getById(sysMenuEx.getParentId());
            Optional.ofNullable(parentMenu).orElseThrow(() -> new ApiException("父菜单不存在"));
            getBaseMapper().decrSubCount(sysMenuEx.getParentId());
        }
        childIdList.add(id);
        roleMenuService.removeByMenuIds(childIdList);
    }

    /**
     * 当前登录用户菜单
     *
     * @return List<UserMenuVO>
     */
    @Override
    public Set<UserMenuVO> userMenu() {
        Set<UserMenuVO> retList = new HashSet<>();
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getState, 1);
        List<SysMenu> list = list(queryWrapper);
        list.forEach(data -> {
            UserMenuVO userMenuVO = new UserMenuVO();
            BeanUtils.copyProperties(data, userMenuVO);
            retList.add(userMenuVO);
        });
        return retList;
    }

    @Override
    public List<MenuTreeVO> treeSimpleMenu() {
        List<SysMenu> list = list();
        Map<Long, List<SysMenu>> menuMap = list.stream().collect(Collectors.groupingBy(SysMenu::getParentId));
        return handlerTreeMenu(menuMap, 0L);
    }

    /**
     * 获取菜单详情
     *
     * @param id id
     * @return MenuDetailVO
     */
    @Override
    public MenuDetailVO getMenu(Long id) {
        SysMenu sysMenuEx = getById(id);
        Optional.ofNullable(sysMenuEx).orElseThrow(() -> new ApiException("菜单不存在"));
        return setMenuDetail(sysMenuEx);
    }

    @Override
    public List<CommonTreeVO> treeAppMenu() {
        List<SysMenu> list = list();
        Map<Long, List<SysMenu>> menuMap = list.stream().collect(Collectors.groupingBy(SysMenu::getParentId));
        return handlerCommonTreeMenu(menuMap, 0L);
    }

    /**
     * 迭代处理菜单
     *
     * @param menuMap 数据库数据
     * @param pid     父id
     * @author wujj
     * @since 2020/6/9 18:25
     */
    private List<CommonTreeVO> handlerCommonTreeMenu(Map<Long, List<SysMenu>> menuMap, Long pid) {
        //父菜单数据
        List<SysMenu> sysMenus = menuMap.get(pid);
        List<CommonTreeVO> retList = new ArrayList<>();
        if (CollectionUtil.isEmpty(sysMenus)) {
            return retList;
        }
        sysMenus.forEach(sysMenu -> {
            CommonTreeVO commonTreeVO = new CommonTreeVO();
            commonTreeVO.setId(sysMenu.getId());
            commonTreeVO.setName(sysMenu.getName());
            retList.add(commonTreeVO);
            //查找子节点
            if (sysMenu.getSubCount() > 0) {
                commonTreeVO.setChildList(handlerCommonTreeMenu(menuMap, sysMenu.getId()));
            }
        });
        return retList;
    }

    /**
     * 迭代处理菜单
     *
     * @param menuMap 数据库数据
     * @param pid     父id
     * @author wujj
     * @since 2020/6/9 18:25
     */
    private List<MenuTreeVO> handlerTreeMenu(Map<Long, List<SysMenu>> menuMap, Long pid) {
        //父菜单数据
        List<MenuTreeVO> retList = new ArrayList<>();
        List<SysMenu> sysMenus = menuMap.get(pid);
        if (CollectionUtil.isEmpty(sysMenus)) {
            return retList;
        }
        sysMenus.forEach(sysMenu -> {
            MenuTreeVO commonTreeVO = new MenuTreeVO();
            commonTreeVO.setId(sysMenu.getId());
            commonTreeVO.setName(sysMenu.getName());
            commonTreeVO.setType(sysMenu.getType());
            commonTreeVO.setSortBy(sysMenu.getSortBy());
            retList.add(commonTreeVO);
            //查找子节点
            if (sysMenu.getSubCount() > 0) {
                commonTreeVO.setChildList(handlerTreeMenu(menuMap, sysMenu.getId()));
            }
        });
        return retList;
    }


    private MenuDetailVO setMenuDetail(SysMenu sysMenuEx) {
        MenuDetailVO menuDetail = new MenuDetailVO();
        BeanUtils.copyProperties(sysMenuEx, menuDetail);
        menuDetail.setId(sysMenuEx.getId());
        //查找父菜单
        if (0 == sysMenuEx.getParentId()) {
            menuDetail.setParentName("无");
        } else {
            String parentName = getById(sysMenuEx.getParentId()).getName();
            menuDetail.setParentName(parentName);
        }
        return menuDetail;
    }

}
